package org.covalence.core.util;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.apache.log4j.Logger;
import org.covalence.core.Observable;

@SuppressWarnings("unchecked")
public class CList implements Observable, List {

	private List _delegate;

	private Observable _parent;

	private String _propertyName;

	private static Logger log = Logger.getLogger(CList.class);

	public CList(Object delegate) {
		super();
		this._delegate = (List) delegate;
	}
	
	public Object getParent() {
		return this._parent;
	}

	public void setParent(Observable parent) {
		this._parent = parent;
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this._parent.removePropertyChangeListener(listener);		
	}

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		this._parent.removePropertyChangeListener(listener);		
	}

	public void setNestedPropertyName(String propertyName) {
		this._propertyName = propertyName;
	}
	
	public void addNestedObservable(Observable obs, String propertyName) {
		throw new UnsupportedOperationException("Cannot nest observables inside CList");
	}

	public void propertyChange(PropertyChangeEvent evt) {
	}

	public PropertyChangeListener[] getPropertyChangeListeners() {
		return null;
	}
	
	public void add(int index, Object element) {
		_delegate.add(index, element);
		_notify();
	}

	public boolean add(Object o) {
		boolean result = _delegate.add(o);
		_notify();
		return result;
	}

	public boolean addAll(Collection c) {
		boolean result = _delegate.addAll(c);
		_notify();
		return result;
	}

	public boolean addAll(int index, Collection c) {
		boolean result = _delegate.addAll(index, c);
		_notify();
		return result;
	}

	public void clear() {
		_notify();
		_delegate.clear();
	}

	public boolean contains(Object o) {
		boolean result = _delegate.contains(o);
		return result;
	}

	public boolean containsAll(Collection c) {
		return _delegate.containsAll(c);
	}

	public boolean equals(Object o) {
		return _delegate.equals(o);
	}

	public Object get(int index) {
		return _delegate.get(index);
	}

	public int hashCode() {
		return _delegate.hashCode();
	}

	public int indexOf(Object o) {
		return _delegate.indexOf(o);
	}

	public boolean isEmpty() {
		return _delegate.isEmpty();
	}

	public Iterator iterator() {
		return _delegate.iterator();
	}

	public int lastIndexOf(Object o) {
		return _delegate.lastIndexOf(o);
	}

	public ListIterator listIterator() {
		return _delegate.listIterator();
	}

	public ListIterator listIterator(int index) {
		return _delegate.listIterator(index);
	}

	public Object remove(int index) {
		Object result = _delegate.remove(index);
		_notify();
		return result;
	}

	public boolean remove(Object o) {
		boolean result = _delegate.remove(o);
		_notify();
		return result;
	}

	public boolean removeAll(Collection c) {
		boolean result = _delegate.removeAll(c);
		_notify();
		return result;
	}

	public boolean retainAll(Collection c) {
		boolean result = _delegate.retainAll(c);
		_notify();
		return result;
	}

	public Object set(int index, Object element) {
		Object result = _delegate.set(index, element);
		_notify();
		return result;
	}

	public int size() {
		return _delegate.size();
	}

	public List subList(int fromIndex, int toIndex) {
		return _delegate.subList(fromIndex, toIndex);
	}

	public Object[] toArray() {
		return _delegate.toArray();
	}

	public Object[] toArray(Object[] a) {
		return _delegate.toArray(a);
	}
	
	private void _notify() {
		if (_propertyName == null) {
			log.warn("Property name was never set, cannot notify.  " +
					"Try nesting this object inside another observable.");
		} else if (_parent == null) {
			log.warn("Parent is null, cannot notify.  " +
					"Make sure the parent property is set.");
		} else {
			_parent.propertyChange(
					new PropertyChangeEvent(_parent, _propertyName, null, this));
		}
	}
}